import { Injectable } from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
import { $Enums } from "@prisma/client";

import { AppUserType } from "@/core/auth/constants";
import { PrismaService } from "@/core/db/prisma.service";
import BusinessException from "@/core/exception/BusinessException";
import { BcryptUtils } from "@/core/utils/BcryptUtils";
import { JwtPayloadVO } from "@/core/vo/jwt-payload.vo";

import { LoginVo } from "./vo/login.vo";

@Injectable()
export class LoginService {
    constructor(
        private readonly prismaService: PrismaService,
        private readonly jwtService: JwtService
    ) {}

    async register(username: string, password: string, channel: $Enums.Channel) {
        const user = await this.prismaService.user.findFirst({
            where: {
                OR: [{ username }],
                AND: {
                    isDeleted: false
                }
            }
        });

        if (user) throw new BusinessException("USER_EXIST");

        const hashedPassword = await BcryptUtils.hashPassword(password);

        await this.prismaService.user.create({
            data: {
                username,
                nickname: "ikun" + Date.now(),
                channel,
                sn: "" + Date.now(),
                password: hashedPassword,
                // avatar: `https://api.dicebear.com/9.x/lorelei/svg?seed=${Date.now()}`
                avatar: `http://localhost:7001/image/avatar.jpg`
            }
        });
    }

    async login(username: string, password: string, ip: string) {
        const user = await this.prismaService.user.findUnique({
            where: {
                username,
                isDeleted: false
            }
        });

        if (!user) throw new BusinessException("USER_NOT_FOUND");
        if (user.isDisabled) throw new BusinessException("ACCOUNT_LOCKED");

        const isMatch = await BcryptUtils.comparePassword(password, user.password);
        if (!isMatch) throw new BusinessException("PASSWORD_EXPIRED");

        await this.prismaService.user.update({
            where: {
                id: user.id
            },
            data: {
                lastLoginIp: ip,
                lastLoginAt: new Date()
            }
        });

        // sign 方法要求传入一个纯对象，不能是类实例，所以要结构一下
        const jwt = this.jwtService.sign({ ...new JwtPayloadVO(user.id, username, AppUserType.FRONTEND_USER) });

        return new LoginVo(user, jwt);
    }

    logout(id: number) {
        return id;
    }
}
